#include "http_session.h"
#include "http_parser.h"
#include "qtch/config.h"

namespace qtch {
namespace http {

static ConfigVar<int64_t>::ptr g_http_session_expire_ms = 
    Config::LookUp<int64_t>("tcp.http.session_expire_ms",1 * 60 * 60,"http session expire time(ms)");

static int64_t s_http_session_expire_ms;

struct __HTTP_SESSION_INIT_STRUCT
{
    __HTTP_SESSION_INIT_STRUCT(){
        s_http_session_expire_ms = g_http_session_expire_ms->getValue();
        g_http_session_expire_ms->addListener([](const int64_t& _old_value,const int64_t& _new_value){
            s_http_session_expire_ms = _new_value;
        });
    }
};



HttpSession::HttpSession(Socket::ptr sock, bool owner, size_t byteBaseSize)
    :SocketStream(sock,owner)
    ,m_ba(new ByteArray(byteBaseSize)){
    sock->setRecvTimeout(s_http_session_expire_ms);
    sock->setSendTimeout(s_http_session_expire_ms);
}

HttpRequest::ptr HttpSession::recvRequest(){
    m_ba->clearUnused();
    HttpRequestParser::ptr parser(new HttpRequestParser);
    uint64_t buff_size = HttpRequestParser::GetHttpRequestBufferSize();
    std::shared_ptr<char> buffer(
        new char[buff_size], [](char * ptr){
            delete[] ptr;
        });
    char * data = buffer.get();
    int offset = 0;
    do {
        int len = 0;
        if(m_ba->getReadSize()>0){
            len = (buff_size - offset > m_ba->getReadSize() ? m_ba->getReadSize() : buff_size - offset);
            m_ba->read(data + offset, len);
        } else {
            len = read(data + offset, buff_size - offset);
        }
        if(len <= 0){
            close();
            return nullptr;
        }
        len += offset;
        size_t nparse = parser->execute(data,len);
        if(parser->hasError()){
            close();
            return nullptr;
        }
        offset = len - nparse;
        if( offset == (int)buff_size){
            close();
            return nullptr;
        }
        if(parser->isFinished()){
            break;
        }
    }while(true);
    int length = parser->getContentLength();
    if(length > 0){
        std::string body;
        body.resize(length);
        int len = 0;
        if(length >= offset){
            memcpy(&body[0],data,offset);
            len = offset;
        } else {
            memcpy(&body[0],data,length);
            len = length;
            m_ba->write(data+length,offset - length);
        }
        length -= offset;
        if(length > 0){
            if(readFixSize(&body[len],length) <= 0){
                close();
                return nullptr;
            }
        }
        parser->getData()->setBody(body);
    }
    parser->getData()->init();
    parser->getData()->initParam();
    return parser->getData();

}

int HttpSession::sendResponse(HttpResponse::ptr rsp){
    std::stringstream ss;
    ss << rsp;
    std::string data = ss.str();
    return writeFixSize(data.c_str(),data.size());
}





}
}

